package org.jheuristics.ga.multiObjective;

/**
 * TODO
 *
 * @author Marcell Manfrin, marcell@ourgrid.org, Oct 28, 2005
 * @author Thiago Emmanuel Pereira da Cunha Silva, thiagoepdc at ourgrid.org, Oct 28, 2005
 */
public class DefaultMultiObjetiveFitness implements MultiObjectiveFitness {
	private Comparable[] fitness;
	private double density;
	private double rawFitness;

	/**
	 * TODO
	 *
	 * @param fitness
	 */
	public DefaultMultiObjetiveFitness(Comparable[] fitness) {
		if (null == fitness) {
			// TODO: ERROR MSG
			throw new NullPointerException();
		}
		this.fitness = fitness;
	}

	/**
	 * TODO
	 *
	 * @return
	 * @see org.jheuristics.ga.multiObjective.MultiObjectiveFitness#getObjectives()
	 */
	public Comparable[] getObjectives() {
		return fitness;
	}

	/**
	 * TODO
	 *
	 * @return
	 * @see org.jheuristics.ga.multiObjective.MultiObjectiveFitness#getDensity()
	 */
	public double getDensity() {
		return density;
	}

	/**
	 * TODO
	 *
	 * @param density
	 * @see org.jheuristics.ga.multiObjective.MultiObjectiveFitness#setDensity(double)
	 */
	public void setDensity(double density) {
		if (0 > density) {
			throw new IllegalArgumentException();
		}
		this.density = density;
	}

	/**
	 * TODO
	 *
	 * @param o
	 * @return
	 * @see org.jheuristics.ga.multiObjective.MultiObjectiveFitness#relatesTo(java.lang.Object)
	 */
	public int relatesTo(Object o) {
		if (!(o instanceof MultiObjectiveFitness)) {
			// TODO: ERROR MSG
			if (null == o) {
				throw new NullPointerException();
			}
			throw new ClassCastException();
		}
		Comparable[] otherFit = ((MultiObjectiveFitness) o).getObjectives();
		if (null == otherFit) {
			// TODO ERROR MSG
			throw new NullPointerException();
		}
		if (otherFit.length != fitness.length) {
			// TODO: ERROR MSG
			throw new IllegalArgumentException();
		}

		int firstDominateSecond = 0;
		int secondDominateFirst = 0;
		for (int i = 0; i < fitness.length; i++) {
			int result = compare(fitness[i], otherFit[i]);
			if (result < 0) {
				// fitness[i] worst than otherFit[i]
				secondDominateFirst = 1;
			} else {
				if (result > 0) {
					// fitness[i] best than otherFit[i]
					firstDominateSecond = 1;
				}
			}
		}
		return firstDominateSecond - secondDominateFirst;
	}

	/**
	 * TODO
	 *
	 * @param fitness1
	 * @param fitness2
	 * @return
	 */
	protected int compare(Comparable fitness1, Comparable fitness2) {
		if (fitness1 == fitness2) {
			return 0;
		}
		if (null == fitness1) {
			return -fitness2.compareTo(fitness1);
		} else {
			return fitness1.compareTo(fitness2);
		}
	}

	/**
	 * TODO
	 *
	 * @param o
	 * @return
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	public int compareTo(Object o) {
		if (null == o) {
			// TODO: ERROR MSG
			throw new NullPointerException();
		}
		if(!(o instanceof MultiObjectiveFitness )) { 
			// TODO: ERROR MSG
			throw new ClassCastException();
		}
		double otherDouble = ((MultiObjectiveFitness) o).toDouble();
		double thisDouble = this.toDouble();
		if (thisDouble > otherDouble) {
			return -1;
		}
		if (thisDouble < otherDouble) {
			return 1;
		}
		return 0;
	}

	/**
	 * TODO
	 *
	 * @param rawFitness
	 * @see org.jheuristics.ga.multiObjective.MultiObjectiveFitness#setRawFitness(double)
	 */
	public void setRawFitness(double rawFitness) {
		this.rawFitness = rawFitness;
	}

	/**
	 * TODO
	 *
	 * @return
	 * @see org.jheuristics.ga.multiObjective.MultiObjectiveFitness#getRawFitness()
	 */
	public double getRawFitness() {
		return this.rawFitness;
	}

	/**
	 * TODO
	 *
	 * @return
	 * @see org.jheuristics.ga.DoubleFitness#toDouble()
	 */
	public double toDouble() {
		return getRawFitness() + getDensity();
	}

}
